////////////////////////////////////////////////////////////////////////////////

#include "gui.h"

////////////////////////////////////////////////////////////////////////////////


GUI::GUI()
:m_Screen(NULL), m_Player(NULL), m_Bullet(NULL)
{
    // Init SDL
    SDL_Init( SDL_INIT_EVERYTHING );

    const int width = 640;
    const int height = 480;
    const int bitsPerPixel = 32;

    //Set up the screen
    m_Screen = SDL_SetVideoMode( width, height, bitsPerPixel, SDL_HWSURFACE );

    //Set the window caption
    SDL_WM_SetCaption( "Shoot the music", NULL );

    // Load player image
    m_Player = LoadImage("player.png");

    // Load bullet image
    m_Bullet = LoadImage("bullet.png");
}


////////////////////////////////////////////////////////////////////////////////


GUI::~GUI()
{
    SDL_Quit();
}


////////////////////////////////////////////////////////////////////////////////


void GUI::Start()
{
    // SDL event
    SDL_Event event;

    while(true)
    {
        // Start fps timer
        m_FPS.Start();

        // Process user input
        while( SDL_PollEvent(&event) )
        {
            if (event.type == SDL_QUIT)
                return;
            ProcessEvent(event);
        }

        // Logic
        m_Engine.ProcessLogic();

		Draw();

        //Cap the frame rate
        Wait();
    }
}


////////////////////////////////////////////////////////////////////////////////


void GUI::ProcessEvent( const SDL_Event& _event )
{
    // Engine event
    Engine::Event engineEvent = Engine::INVALID;

    // Convert from SDL to internal engine event
    switch (_event.type)
    {
    case SDL_KEYDOWN:
        {
            switch (_event.key.keysym.sym)
            {
            case SDLK_w:
                engineEvent = Engine::W_DOWN;
                break;
            case SDLK_s:
                engineEvent = Engine::S_DOWN;
                break;
            case SDLK_a:
                engineEvent = Engine::A_DOWN;
                break;
            case SDLK_d:
                engineEvent = Engine::D_DOWN;
                break;
            default:
                break;
            }

            break;
        }

    ////////////////////////////////////////

    case SDL_KEYUP:
        {
            switch (_event.key.keysym.sym)
            {
            case SDLK_w:
                engineEvent = Engine::W_UP;
                break;
            case SDLK_s:
                engineEvent = Engine::S_UP;
                break;
            case SDLK_a:
                engineEvent = Engine::A_UP;
                break;
            case SDLK_d:
                engineEvent = Engine::D_UP;
                break;
            default:
                break;
            }

            break;
        }

    ////////////////////////////////////////

    case SDL_MOUSEBUTTONDOWN:
        {
            switch (_event.button.button)
            {
            case SDL_BUTTON_LEFT:
                engineEvent = Engine::MOUSE1_DOWN;
                break;
            default:
                break;
            }
            break;
        }

    ////////////////////////////////////////

    case SDL_MOUSEBUTTONUP:
        {
            switch (_event.button.button)
            {
            case SDL_BUTTON_LEFT:
                engineEvent = Engine::MOUSE1_UP;
                break;
            default:
                break;
            }
            break;
        }

    ////////////////////////////////////////

    case SDL_MOUSEMOTION:
        m_Engine.ProcessMouseMotion(_event.motion.x, _event.motion.y);
        break;

    default:
        return;
    }

    m_Engine.ProcessEvent(engineEvent);
}


////////////////////////////////////////////////////////////////////////////////


void GUI::Draw()
{
    // Fill the screen white
    SDL_FillRect( m_Screen,
                  &m_Screen->clip_rect,
                  SDL_MapRGB( m_Screen->format, 0xAA, 0xFF, 0xAA ) );

    // Get battlefield
    const Battlefield& battlefield = m_Engine.GetBattlefield();

    // Get player
    const Player& player = battlefield.GetPlayer();

    DrawMovingObject( player, m_Player );

    Battlefield::Bullets::const_iterator it = battlefield.GetBullets().begin();
    while ( it != battlefield.GetBullets().end() )
    {
        DrawMovingObject( **it, m_Bullet );
        it++;
    }

    // Update the screen
    SDL_Flip( m_Screen );
}


////////////////////////////////////////////////////////////////////////////////


void GUI::DrawMovingObject( const MovingObject& _object, SDL_Surface* _surface )
{
    // Get player position
    STM::Position position = _object.GetPosition();

    // Draw player
    int x = static_cast<int>(position.first);
    int y = static_cast<int>(position.second);
    ApplySurface(x, y, _surface, m_Screen);
}


////////////////////////////////////////////////////////////////////////////////


void GUI::Wait()
{
    // Frames per second
    const int FPS = 30;

    if( m_FPS.Milliseconds() < 1000 / FPS )
        SDL_Delay( ( 1000 / FPS ) - m_FPS.Milliseconds() );
}


////////////////////////////////////////////////////////////////////////////////


SDL_Surface* GUI::LoadImage( std::string _fileName )
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;

    //The optimized surface that will be used
    SDL_Surface* optimizedImage = NULL;

    //Load the image
    loadedImage = IMG_Load( _fileName.c_str() );

    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormat( loadedImage );

        //Free the old surface
        SDL_FreeSurface( loadedImage );

        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0xFF, 0xFF, 0xFF ) );
        }
    }

    //Return the optimized surface
    return optimizedImage;
}


////////////////////////////////////////////////////////////////////////////////


void GUI::ApplySurface( int x,
                        int y,
                        SDL_Surface* source,
                        SDL_Surface* destination,
                        SDL_Rect* clip /* = NULL */ )
{
    //Holds offsets
    SDL_Rect offset;

    //Get offsets
    offset.x = x;
    offset.y = y;

    //Blit
    SDL_BlitSurface( source, clip, destination, &offset );
}


////////////////////////////////////////////////////////////////////////////////
